#include"../../inc/net/TcpConnection.h"
#include"../../libs/Mylog.h"
#include"../../inc/net/EventLoop.h"
#include"../../inc/net/Address.h"
#include"../../inc/net/SocketIO.h"
#include"../../inc/net/Noncopyable.h"
#include"../../inc/net/Socket.h"
#include<functional>
#include<memory>
#include<string>


namespace SC
{
    using TC = TcpConnection;
    TC::TcpConnection(int fd, EventLoop* loop)
    : _sock(fd), _sio(fd), _isShutdownWrite(false), _local(getLocal()), _peer(getPeer()), _loop(loop)
    {
    }

    TC::~TcpConnection()
    {
        this->shutdown();
    }

    string TC::recv()
    {
        char buf[65535] = {0};
        size_t len;
        _sio.readn((char*)&len, sizeof(len));
        _sio.readn(buf, len);
        return string(buf);
    }

    void TC::send(const string& msg)
    {
        size_t len = msg.size();
        _sio.writen((char*)&len, sizeof(size_t));
        _sio.writen(msg.c_str(), strlen(msg.c_str()));
    }

    void TC::sendInLoop(const string& msg)
    {
        _loop->runInLoop(std::bind(&TcpConnection::send, this, msg));
    }

    string TC::address() const
    {
        std::ostringstream oss;
        oss << _local.getIP() << ":" << _local.getPort() << ">>" << _peer.getIP() << ":" << _peer.getPort();
        return oss.str();
    }

    void TC::shutdown()
    {
        if(!_isShutdownWrite)
        {
            _sock.Shutdown();
            _isShutdownWrite = true;
        }
    }

    int TC::fd() const
    {
        return _sock.fd();
    }

    void TC::setConnectCB(const TcpConnectionCallBack& cb)
    {
        _cb_connection = std::move(cb);
    }

    void TC::setMessageCB(const TcpConnectionCallBack& cb)
    {
        _cb_msg = std::move(cb);
    }

    void TC::setCloseCB(const TcpConnectionCallBack& cb)
    {
        _cb_close = std::move(cb);
    }

    void TC::handleConnectCB()
    {
        if(_cb_connection)
        {
            _cb_connection(shared_from_this());
        }
    }

    void TC::handleMessageCB()
    {
        if(_cb_msg)
        {
            _cb_msg(shared_from_this());
        }
    }

    void TC::handleCloseCB()
    {
        if(_cb_close)
        {
            _cb_close(shared_from_this());       
        }
    }

    Address TC::getLocal()
    {
        sockaddr_in localaddr;
        socklen_t len = sizeof(localaddr);
        memset(&localaddr, 0, (size_t)len);
        int ret = getsockname(fd(), (sockaddr*)&localaddr, &len);
        if(-1 == ret)
            logError("getsockname err");
        
        return Address(localaddr);
    }

    Address TC::getPeer()
    {
        sockaddr_in peeraddr;
        socklen_t len = sizeof(peeraddr);
        memset(&peeraddr, 0, (size_t)len);
        int ret = getpeername(fd(), (sockaddr*)&peeraddr, &len);
        if(-1 == ret)
            logError("getsockname err");
        
        return Address(peeraddr);
    }
}